package com.jiangyg.devtools.ui.table;

import com.jiangyg.devtools.DevtoolsException;
import com.jiangyg.devtools.toolkit.ReflectionUtils;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.lang.StringUtils;

import javax.swing.table.AbstractTableModel;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 类描述：可编辑的表格模型
 *
 * @author jiangyg
 * @date 2023-08-26
 */
public abstract class AbstractEditableTableModel<T> extends AbstractTableModel {

    private final List<T> dataList = new ArrayList<>();

    private List<ColumnDefinition> columns;

    public AbstractEditableTableModel() {
        initialization();
    }

    @Override
    public int getRowCount() {
        return dataList.size();
    }

    @Override
    public int getColumnCount() {
        return columns.size();
    }

    @Override
    public String getColumnName(int column) {
        return columns.get(column).getTitle();
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        try {
            final T data = dataList.get(rowIndex);
            final ColumnDefinition column = columns.get(columnIndex);
            // 数据为空直接返回空
            if (data == null) {
                return StringUtils.EMPTY;
            }
            // 读取属性值
            final String property = column.getProperty();
            final Object value = BeanUtilsBean.getInstance().getPropertyUtils().getProperty(data, property);
            if (value == null) {
                return StringUtils.EMPTY;
            }
            return value;
        } catch (Exception ex) {
            throw new DevtoolsException(String.format("读取行[%d]列[%d]单元格失败", rowIndex, columnIndex), ex);
        }
    }

    @Override
    public void setValueAt(Object value, int rowIndex, int columnIndex) {
        try {
            final T data = dataList.get(rowIndex);
            final ColumnDefinition definition = getColumnDefinition(columnIndex);
            BeanUtilsBean.getInstance().getPropertyUtils().setProperty(data, definition.getProperty(), value);
            this.fireTableCellUpdated(rowIndex, columnIndex);
        } catch (Exception ex) {
            throw new DevtoolsException(String.format("更新行[%d]列[%d]单元格失败", rowIndex, columnIndex), ex);
        }
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        final ColumnDefinition definition = getColumnDefinition(columnIndex);
        return definition.isEditable();
    }

    /**
     * 功能描述：获取列的定义
     *
     * @param columnIndex 列索引
     * @return 列的定义
     */
    public ColumnDefinition getColumnDefinition(int columnIndex) {
        return columns.get(columnIndex);
    }

    /**
     * 功能描述：新增一行数据
     *
     * @param data 数据
     */
    public void addRow(T data) {
        final int size = dataList.size();
        dataList.add(data);
        this.fireTableRowsInserted(size, size);
    }

    /**
     * 功能描述：新增一行数据
     *
     * @param rowIndex 行索引
     * @param data     数据
     */
    public void addRow(int rowIndex, T data) {
        dataList.add(rowIndex, data);
        this.fireTableRowsInserted(rowIndex, dataList.size());
    }

    /**
     * 功能描述：删除指定行
     *
     * @param rowIndex 行索引
     */
    public void removeRow(int rowIndex) {
        dataList.remove(rowIndex);
        this.fireTableRowsDeleted(rowIndex, rowIndex);
    }

    /**
     * 功能描述：清空数据
     */
    public void emptyAllRows() {
        dataList.clear();
        this.fireTableDataChanged();
    }

    public List<T> getDataList() {
        return dataList;
    }

    /**
     * 功能描述：初始化操作
     */
    private void initialization() {
        // 初始化列集合
        final Class<?> clazz = ReflectionUtils.getSuperClassGenericType(this.getClass(), 0);
        final Field[] fields = clazz.getDeclaredFields();
        this.columns = Arrays.stream(fields)
                .filter(field -> field.getAnnotation(Column.class) != null)
                .map(field -> {
                    final ColumnDefinition definition = new ColumnDefinition();

                    final Column column = field.getAnnotation(Column.class);

                    definition.setProperty(field.getName());
                    definition.setTitle(column.title());
                    definition.setOrder(column.order());
                    definition.setWidth(column.width());
                    definition.setEditable(column.editable());
                    definition.setRender(column.type().render);
                    definition.setEditor(column.type().editor);

                    return definition;
                })
                .sorted(Comparator.comparingInt(ColumnDefinition::getOrder))
                .collect(Collectors.toList());
    }

}
